import { type Component } from "solid-js"
import type { JSX } from "solid-js/jsx-runtime"

export type UnionClassType = string | ClassListType | (string | ClassListType)[]

export interface IClass {
    classes?: UnionClassType
}

export type BsVariant = "primary"
    | "secondary"
    | "success"
    | "danger"
    | "warning"
    | "info"
    | "light"
    | "dark";

export type ClassListType = JSX.CustomAttributes<any>['classList']

export type FireCustomAttributes<T> = Omit<JSX.CustomAttributes<T>, 'classList'> & {
    classList?: UnionClassType
}

export const wrapClasses = (classes?: UnionClassType): ClassListType => {
    if (classes === undefined || classes === null) {
        return {}
    }

    if (typeof classes === 'string') {
        return {
            [classes]: true
        }
    }

    if (Array.isArray(classes)) {
        const combined = classes.reduce((p, c) => {
            p = p ?? {} as ClassListType;

            if (IsString(c)) {
                return {
                    ...p as ClassListType,
                    [c]: true
                }
            }
            else {
                return {
                    ...p as ClassListType,
                    ...c
                }
            }
        }, {} as ClassListType) as ClassListType

        return combined;
    }

    return classes
}

export const IsString = (value: any): value is string => {
    return typeof value === 'string';
}

export const wrapOptions = (options?: any) => {
    if (!options) { return {} }

    const wrapped = Object.entries(options).reduce((p, c) => {
        p = p || {};
        p[`data-bs-${c[0]}`] = `${c[1]}`;
        return p;
    }, {} as { [key: string]: any });

    return wrapped
}

export interface RefComponent<T> {
    onRef?: (ref?: T) => void
}

export type HtmlElementOrComponent = keyof JSX.IntrinsicElements | Component

export type NullableAsComponentProps<T extends HtmlElementOrComponent> = T extends keyof JSX.IntrinsicElements
    ? JSX.IntrinsicElements[T]
    : T extends (props: infer P) => JSX.Element
    ? P
    : never;
